import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;

public class Parser {
	
private TablaSimbolos ts; //Tabla de s�mbolos que iremos sintetizando
private ArrayList<String> cod=new ArrayList<String>();//c�digo para nuestra m�quina pila P que iremos sintetizando
private Integer dir;
private Scanner scanner;//nuestro analizador l�xico
private ArrayList<String> err;
private ArrayList<String> pend;
private String categoria=null;
String lex="";
private String tipo="";
private int etq=0;
boolean Terminar=false;
boolean encontrado=false;
private int contFilas=0;
boolean noAvanzaToken=false;
private int campoDesp;
private int nivel;
private int numNiveles;
private int postipo;
private String tipoReturn;
private ArrayList<Integer> dirRetorno;
private boolean par;


/*Es el parser el que crea el scanner con el fichero input, 
el cual ir� leyendo tokens de 1 en 1 y pas�ndoselos al parser*/

public Parser(Reader input) throws IOException {
	
	ts=null;
	cod=new ArrayList<String>();
	dir=0;
	numNiveles=0;
	postipo=0;
	nivel=0;
	dirRetorno=new ArrayList<Integer>();
	err=new ArrayList<String>();
	pend=new ArrayList<String>();
	//En err guardaremos la lista de errores de nuestro programa
	scanner = new Scanner(input);
    scanner.inicializa();
    prog();//Que implementa nuestra gram�tica de la memoria
    
    if (err.size()!=0)
    	Interface.mostrarErrores(err);//Si tenemos errores, los mostramos
    
    /*Si no nos ha dado fallo y no tenemos errores, mostramos el c�digo de m�quina pila
    en el panel de la mitad y lo guardamos en el fichero*/
    String codAux="";
    for(int i=0;i<cod.size();i++)codAux+=(i+1)+":"+cod.get(i)+"\n";
    if(Terminar==false && err.size()==0) 
    	{Interface.setTextArea2(codAux);generaCod();}
}

private String ERROR(String error) {
	contFilas=scanner.dameContFilas();
    err.add( "Error en la linea "+Integer.toString(contFilas)+". "+error);
    Terminar=true;
    return "err";
	
}

private void error() {
	if (categoria.equals("ERROR")){
		contFilas=scanner.dameContFilas();
		err.add( "Error en la linea "+Integer.toString(contFilas)+". Categoria lexica no reconocida.");
	}	
}


private void generaCod() {//Guardamos el c�digo de la m�quina P en el fichero p
	try{
		String codAux="";
		for(int i=0;i<cod.size();i++)codAux+=cod.get(i)+"\n";
	PrintWriter archivoSalida = new PrintWriter(new FileWriter("p")); 
	archivoSalida.print(codAux);
	archivoSalida.close(); } 
	
	catch (IOException e) { 

	System.out.println("Excepcion Entrada/Salida"); 

	} 
}

public ArrayList<String> getError(){	
	return err;
}

public void inicializar(Scanner scanner1){	
	scanner=scanner1;	
}

public void emite(String instr){
	//Funci�n que ir� concatenando las instrucciones de la maquina pila p.
	//cod=cod+instr+"\n";
	cod.add(instr);
	etq++;
}

/*Esta funci�n nos dice si el operando ope es compatible con los
operandos de tipo tipo1 y tipo2*/

public boolean compatibles(String ope, String tipo1, String tipo2){
	if (ope.equals("==")||ope.equals("!=")){
		if (tipo1.equals("null")&&tipo2.equals("null"))return true;
		else if (tipo1.equals("null")&&ts.props(ref(tipo2)).tipo().t().equals(tipot.puntero)
				||(tipo2.equals("null")&&ts.props(ref(tipo1)).tipo().t().equals(tipot.puntero)))
			return true;
		else if (tipo1.equals("null")|| tipo2.equals("null"))return false;
			else if (!tipo1.equals("err")&&!tipo2.equals("err"))return true;//tanto uno como otro pueden ser entero o real
	}
	if ( ope.equals("<")||ope.equals(">")||ope.equals(">=")||
			ope.equals("<=")||ope.equals("==")||ope.equals("!=")
			||ope.equals("+")||ope.equals("-")||ope.equals("*")||
			ope.equals("/")){//op2		
				if (!tipo1.equals("err")&&!tipo2.equals("err"))return true;//tanto uno como otro pueden ser entero o real
				}
	if ( ope.equals("||")||ope.equals("&&")||ope.equals("%")){
			if ( (tipo1.equals("integer"))&&(tipo2.equals("integer"))) return true;
			else return false;
				}
	if ( ope.equals("=")){
		if ( (tipo1.equals("integer"))&&(tipo2.equals("real"))||(tipo1.equals("err")||tipo2.equals("err"))) return false;
		else return true;
	}else if(tipo1.equals(tipo2))return true;
	return false;
}

/*Esta funci�n nos dice si el operando ope es compatible con el
operando de tipo tipo1*/
public boolean compatible(String ope, String tipo1){
	
	if( ope.equals("!")){
		if (tipo1.equals("entero")) return true;
		else return false;
	}	
	if( (ope.equals("-")||ope.equals("cInt")||ope.equals("cReal"))&&(tipo1.equals("err"))){
		 return true;	
	}
	return true;
}

/*Esta funcion nos devuelve el tipo del resultado de la operacion ope
con los operandos de tipo tipo1 y tipo2*/
public String funop(String ope,String tipo1, String tipo2){
	if (tipo1.equals("err")||(tipo2.equals("err")))return "err";
	if (ope.equals("<")||ope.equals(">")||ope.equals(">=")||
			ope.equals("<=")||ope.equals("==")||ope.equals("!=")){		
				return "integer";
				}
	else if ( ope.equals("+")||ope.equals("-")||ope.equals("*")||
	ope.equals("/")){
		if ( tipo1.equals("integer")&& tipo2.equals("integer") ) return "integer";
		else if ( tipo1.equals("real")&& tipo2.equals("real") ) return "real";
		else return "integer";
	}
	
	else if ( ope.equals("||")||ope.equals("&&")||ope.equals("%")){
				if ( tipo1.equals("integer")&& tipo2.equals("integer") ) return "integer";
				
			}
	
	else if ( ope.equals("=")){
		if ( tipo1.equals("real") ) return "real";
		else if ( tipo1.equals("integer")&&tipo1.equals("integer") ) return "integer";
		
	}

		return "err";
}

//Nos devuelve el tipo de la categor�a
public String dameTipo(String entrada){
	if ((entrada.equals("NUMENTERO"))||(entrada.equals("NUMCERO")))return "integer";
	if(entrada.equals("NUMDECIMAL")||entrada.equals("NUMEXPONENCIAL"))return "real";
	return "";
}

//Esta funci�n nos devuelve el tipo del resultado de la operaci�n ope
//con el operandos de tipo tipo1 
public String funopUnario(String op,String tipo1){
	if (tipo1.equals("err"))return "err";
	if ( op.equals("!")){
		if ( tipo1.equals("entero")) return "entero";
		}
	
	else if ( op.equals("-")){
		return tipo1;
	}
	
	else if ( op.equals("cInt")){
		return "integer";
	}
	
	else if ( op.equals("cReal")){
		return "real";
	}
	return "err";
}

//Aqu� empieza nuestra gram�tica de la memoria
private String prog() {
	
	consumeToken();	
		ts= new TablaSimbolos();
		inicio();
		Decs();
		parcheaInicio(numNiveles,dir);
		if(pend.size()>0)return ERROR("Hay tipos pendientes de declarar;");
		Accs();
		if(Terminar==true)return "err";
		emite("STOP");
		//}
	return "";
}

private void parcheaInicio(int numNiveles, int tamDatos) {
	cod.remove(0);
	cod.add(0,"apila("+(numNiveles+2)+")");
	cod.remove(2);
	cod.add(2,"apila("+(1+numNiveles+tamDatos)+")");
	cod.remove(4);
	cod.add(4,"ir-a("+(etq+1)+")");
	
}

private void inicio() {
	emite("apila(...)");
	emite("desapila-dir(1)");
	emite("apila(...)");
	emite("desapila-dir(0)");
	emite("ir-a(...)");
	
}

private void Decs() {

	Dec();

	RDecs();
	
}
private void RDecs() {
	
		Dec();
		if (categoria.equals("PALRES") && ((scanner.dameLexema().equals("rec"))||(scanner.dameLexema().equals("pointer"))||(scanner.dameLexema().equals("tipo"))||(scanner.dameLexema().equals("fun"))||(scanner.dameLexema().equals("real"))||(scanner.dameLexema().equals("int")))
				||(categoria.equals("IDEN") && ts.props(lex)!=null&&ts.props(lex).clase().equals("tipo"))){
			RDecs();
		}

}


private void Dec() {
	if (categoria.equals("PALRES") && (scanner.dameLexema().equals("tipo")))
		DecTipo();
	else if (categoria.equals("PALRES") && (scanner.dameLexema().equals("fun"))){
		int aux=dir;
		dir=0;
		String auxTipo=tipoReturn;
		ArrayList<Integer> auxdir=dirRetorno;
		dirRetorno=new ArrayList<Integer>();
		decfun();
		dirRetorno=auxdir;
		tipoReturn=auxTipo;
		dir=aux;
		
	}
	else	
		DecVar();
}

private void decfun() {
	String id="";
	consumeToken();
	if(categoria.equals("IDEN")){
		id=lex;
		if(ts.existeID(id))ERROR("nombre ya declarado");
		consumeToken();
		ts.aumentaNivel();nivel++;
		numNiveles=Math.max(numNiveles, nivel);
		ArrayList<ParamFun> props=FParams();
		String tipo1=Retorno();
		tipoReturn=tipo1;
		int inicio=etq+1;
		
		ts.addID(id, new RegistroProp(new PropsFun(tipot.fun,props,tipo1,inicio), "fun", inicio),nivel-1);
		Bloque();
		if(!(categoria.equals("PALRES")&&(lex.equals("end"))))ERROR("Se esperaba fin de funcion.");
		else{
			consumeToken();
			ts.disminuyeNivel();nivel--;
			if(!categoria.equals("IDEN"))ERROR("Se esperaba nombre de funcion despues del end");
			else{
				if(!id.equals(lex))ERROR("No concuerda el nombre de fin de funcion con el nombre de la funcion.");
				//if(!id.equals(lex))ERROR("No concuerda el nombre de fin de funcion con el nombre de la funcion.");
				//else ts.addID(lex, new RegistroProp(new PropsFun(tipot.fun,props,tipo1,inicio), "fun", inicio));
				consumeToken();
				if (!(categoria.equals("PUNTOYCOMA")))ERROR("Falta un ;");
			    consumeToken();
			}
			
		}
		
	}
	
	
}

private String Bloque() {
	int etqdir=etq+11;
	prologo(nivel,dir);
	emite("ir-a(...)");
	ArrayList<Integer> etqAux=new ArrayList<Integer>();
	etqAux.add(etq);
	Decs();
	parcheaDir(etqdir,dir);
	parcheaA(etqAux, etq+1);
	
	String tipo=Accs();
	emite("apila(0)");//retorno
	parcheaRetorno(dirRetorno,etq+1);
	epilogo(nivel);
	emite("ir-ind()");
	return tipo;
}

private void parcheaDir(int etqdir, Integer dir2) {
	cod.remove(etqdir);
	cod.add(etqdir,"apila("+(2+dir2)+")");
	
}

private void parcheaRetorno(ArrayList<Integer> dirRetorno2, int etqP) {
	for (int i=0;i<dirRetorno2.size();i++){
		cod.remove(dirRetorno2.get(i)-1);
		cod.add(dirRetorno2.get(i)-1,"ir-a("+etqP+")");
	}
	
}

private void epilogo(int nivel2) {
	emite("apila-dir("+(1+nivel2)+")");	
	emite("apila(2)");			
	emite("resta"); 			
	emite("apila-ind()");			
	emite("apila-dir("+(1+nivel2)+")"); 		
	emite("apila(3)"); 			
	emite("resta"); 				
	emite("copia"); 			
	emite("desapila-dir(0)"); 		
	emite("apila(2)"); 			
	emite("suma"); 				
	emite("apila-ind()"); 			
	emite("desapila-dir("+(1+nivel2)+")");
	
}

private void prologo(int nivel2, int dir2) {
	emite("apila-dir(0)");			
	emite("apila(2)");			
	emite("suma");				
	emite("apila-dir("+(1+nivel2)+")");		
	emite("desapila-ind()");	
	emite("desapila()");
	emite("apila-dir(0)");			
	emite("apila(3)"); 			
	emite("suma");				
	emite("desapila-dir("+(1+nivel2)+")"); 		 
	emite("apila-dir(0)"); 			
	emite("apila(...................)"); 		
	emite("suma"); 				
	emite("desapila-dir(0)");		
}

private String Retorno() {
	if((categoria.equals("PALRES")&&(lex.equals("returns")))){
		consumeToken();
		if((categoria.equals("PALRES")&&(lex.equals("int")||lex.equals("real")))||(categoria.equals("IDEN") 
				&& ts.props(lex)!=null&&ts.props(lex).clase().equals("tipo")&&ts.props(ref(lex)).tipo().t().equals(tipot.puntero))){
			String tipo=lex;if(scanner.dameLexema().equals("int"))tipo="integer";
			consumeToken();
			return tipo;
		}else return ERROR("Tipo de retorno no valido.");
	}
	else
		return "integer";
}

private ArrayList<ParamFun> FParams() {
	if(categoria.equals("PARABIERTO")){
		consumeToken();
		if(categoria.equals("PARCERRADO")){
			consumeToken();
			return new ArrayList<ParamFun>();
		}else return LFParams();
	}else ERROR("Se esperaba un parentesis abierto");
	
	return null;
}

private ArrayList<ParamFun> LFParams() {
	ArrayList<ParamFun> params=new ArrayList<ParamFun>();
	FParam(params);//devuelve param pero fparam no lo hace
	if(categoria.equals("COMA"))
		RLFParams(params);
	if(categoria.equals("PARCERRADO")){
		consumeToken();
		return params;
	}else{
		ERROR("Se esperaba un parentesis cerrado");
		return params;
	}
}

private void RLFParams(ArrayList<ParamFun> params) {
	consumeToken();
	FParam(params);//devuelve param pero fparam no lo hace
	if(categoria.equals("COMA"))
		RLFParams(params);
	if(categoria.equals("PARCERRADO")){
	}else{
		ERROR("Se esperaba un parentesis cerrado");
	}
	
}

private void FParam(ArrayList<ParamFun> params) {
	String tipo;
	if (categoria.equals("PALRES") && ((scanner.dameLexema().equals("real"))||(scanner.dameLexema().equals("int")))
			||(categoria.equals("IDEN") && ts.props(lex)!=null&&ts.props(lex).clase().equals("tipo"))){
		tipo=lex;if(scanner.dameLexema().equals("int"))tipo="integer";
		tipot t;
		if(scanner.dameLexema().equals("int"))tipo="integer";
		if(scanner.dameLexema().equals("real"))t=tipot.real;
		else if(scanner.dameLexema().equals("int"))t=tipot.integer;
		else t=tipot.ref;
		consumeToken();
		if(categoria.equals("AMPERSAND")){
			consumeToken();
			String id=lex;
			params.add(new ParamFun(tipo, id, "pvar",dir));
			if(ts.existeID(lex,nivel))ERROR("Nombre de variable ya utilizado");
			ts.addID(lex, new RegistroProp(new PropsVar(t, tipo,dir,"pvar"), "pvar", ts.props(tipo).tamano()));
			dir+=1;
			consumeToken();
		}else{
			String id=lex;
			params.add(new ParamFun(tipo, id, "var",dir));
			if(ts.existeID(lex,nivel))ERROR("Nombre de variable ya utilizado");
			ts.addID(lex, new RegistroProp(new PropsVar(t, tipo,dir,"var"), "var", ts.props(tipo).tamano()));
			dir+=ts.props(tipo).tamano();
			consumeToken();
		}
	}
	
}

private void DecTipo() {
	consumeToken();//arrays
	if((categoria.equals("PALRES")&&(lex.equals("int")||lex.equals("real")))||(categoria.equals("IDEN") && ts.props(lex)!=null&&ts.props(lex).clase().equals("tipo"))){
		String tipo=lex;
		if(scanner.dameLexema().equals("int"))tipo="integer";
		consumeToken();
		if(categoria.equals("CORCHETEABIERTO")){
			consumeToken();
			if(categoria.equals("NUMENTERO")){
				int numPos=Integer.parseInt(lex);
				consumeToken();
				if(categoria.equals("CORCHETECERRADO")){
					consumeToken();
					if(categoria.equals("IDEN")){
						if(ts.existeID(lex))ERROR("Nombre de variable ya utilizado.");
						else{
							int tamano=ts.props(tipo).tamano()*numPos;
						    ts.addID(lex, new RegistroProp(new PropsArray(tipot.array,tipo,numPos), "tipo", tamano));
						    compruebaPend(lex);
						    consumeToken();
							if (!(categoria.equals("PUNTOYCOMA")))ERROR("Falta un ;");
						    consumeToken();
						}
					}else ERROR("La estructura no concuerda con un array");
				}else ERROR("La estructura no concuerda con un array");
			}else ERROR("La estructura no concuerda con un array");
		}else if(categoria.equals("IDEN")){
					if(ts.existeID(lex))ERROR("Nombre de variable ya utilizado.");
					else{
						int tamano=ts.props(tipo).tamano();
					    ts.addID(lex, new RegistroProp(new Props(tipot.ref,tipo), "tipo", tamano));
					    compruebaPend(lex);
					    consumeToken();
						if (!(categoria.equals("PUNTOYCOMA")))ERROR("Falta un ;");	
					    consumeToken();
					}
				}else ERROR("Se esperaba nombre de variable.");
			
	}else{
		if(categoria.equals("PALRES")&&lex.equals("rec")){
			consumeToken();
			PropsCampos c=Campos();
			if(!(categoria.equals("PALRES")&&lex.equals("endrec")))ERROR("falta fin de registro.");
			consumeToken();
			if(!categoria.equals("IDEN"))ERROR("Se esperaba nombre de registro.");
			else if(ts.existeID(lex))ERROR("Nombre de variable ya utilizado.");
			else{
				ts.addID(lex,new RegistroProp(c, "tipo", campoDesp) );
				compruebaPend(lex);
				consumeToken();
				if (!(categoria.equals("PUNTOYCOMA")))ERROR("Falta un ;");
				consumeToken();
			}
				
		}else if(categoria.equals("PALRES")&&lex.equals("pointer")){
			consumeToken();
			if(ts.existeID(lex)&&ts.props(lex).clase()!="tipo")ERROR(lex+"no es un tipo.");
			String tipo = lex;
			if(scanner.dameLexema().equals("int"))tipo="integer";
			if(!ts.existeID(tipo))pend.add(lex);
			consumeToken();
			if(ts.existeID(lex))ERROR("Nombre ya utilizado.");
			ts.addID(lex, new RegistroProp(new Props(tipot.puntero, tipo), "tipo", 1));
			compruebaPend(lex);
			consumeToken();
			if (!(categoria.equals("PUNTOYCOMA")))ERROR("Falta un ;");
			consumeToken();
			
		}
	}
	
}

private void compruebaPend(String lex) {
	if(pend.contains(lex))
		for(int i=0;i<pend.size();i++){
			if(pend.get(i).equals(lex))pend.remove(i);
		}
	
}

private PropsCampos Campos() {
	campoDesp=0;
	PropsCampos campos=new PropsCampos();
	Campo c=campo();
	if (!(categoria.equals("PUNTOYCOMA")))ERROR("Falta un ;");
	consumeToken();
	campos.add(c);
	RCampos(campos);
	return campos;
	
}

private PropsCampos RCampos(PropsCampos campos) {
	if(!(categoria.equals("PALRES")&&lex.equals("endrec"))){
		Campo c=campo();
		if (!(categoria.equals("PUNTOYCOMA")))ERROR("Falta un ;");
		consumeToken();
		campos.add(c);
		RCampos(campos);
		return campos;
	}
	return campos;
	
}

private Campo campo() {
	if((categoria.equals("PALRES")&&(lex.equals("int")||lex.equals("real")))||(categoria.equals("IDEN") && ts.props(lex)!=null&&ts.props(lex).clase().equals("tipo"))){
		String tipo=lex;
		if(scanner.dameLexema().equals("int"))tipo="integer";
		consumeToken();
		
		 if(categoria.equals("CORCHETEABIERTO")){
			consumeToken();
			if(categoria.equals("NUMENTERO")){
				int numPos=Integer.parseInt(lex);
				consumeToken();
				if(categoria.equals("CORCHETECERRADO")){
					consumeToken();
					if(categoria.equals("IDEN")){
						if(ts.existeID(lex))ERROR("Nombre de variable ya utilizado.");
						else{
							
							int tamano=ts.props(tipo).tamano()*numPos;
						    ts.addID(String.valueOf(postipo), new RegistroProp(new PropsArray(tipot.array,tipo,numPos), "tipo", tamano));
						    compruebaPend(String.valueOf(postipo));
						    
							
						    Campo v=new Campo(lex,tipot.ref,String.valueOf(postipo),campoDesp);
						    consumeToken();
							campoDesp+=ts.props(String.valueOf(postipo)).tamano();
							postipo++;
							return v;
						    
						}
					}else ERROR("La estructura no concuerda con un array");
				}else ERROR("La estructura no concuerda con un array");
			}else ERROR("La estructura no concuerda con un array");
		 }else 
		if(categoria.equals("IDEN")){
			tipot t;
			if(tipo.equals("real"))t=tipot.real;
			else if(tipo.equals("integer"))t=tipot.integer;
			else t=tipot.ref;
			Campo v=new Campo(lex,t,tipo,campoDesp);
			consumeToken();
			campoDesp+=ts.props(tipo).tamano();
			return v;
		}else ERROR("Declaracion de registro erronea.");
	
	}else{
		if(categoria.equals("PALRES")&&lex.equals("rec")){
			consumeToken();
			PropsCampos c=Campos();
			if(!(categoria.equals("PALRES")&&lex.equals("endrec")))ERROR("falta fin de registro.");
			consumeToken();
			if(!categoria.equals("IDEN"))ERROR("Se esperaba nombre de registro.");
			else if(ts.existeID(lex))ERROR("Nombre de variable ya utilizado.");
			else{
				ts.addID(String.valueOf(postipo),new RegistroProp(c, "tipo", campoDesp) );
				compruebaPend(String.valueOf(postipo));
				
				Campo v=new Campo(lex,tipot.ref,String.valueOf(postipo),campoDesp);
			    consumeToken();
				campoDesp+=ts.props(String.valueOf(postipo)).tamano();
				postipo++;
				return v;
			}
				
		}else if(categoria.equals("PALRES")&&lex.equals("pointer")){
			consumeToken();
			if(ts.existeID(lex)&&ts.props(lex).clase()!="tipo")ERROR(lex+"no es un tipo.");
			String tipo = lex;
			if(scanner.dameLexema().equals("int"))tipo="integer";
			if(!ts.existeID(tipo))
				pend.add(lex);
			consumeToken();
			if(ts.existeID(lex))ERROR("Nombre ya utilizado.");
			ts.addID(String.valueOf(postipo), new RegistroProp(new Props(tipot.puntero, tipo), "tipo", 1));
			compruebaPend(String.valueOf(postipo));
			
			Campo v=new Campo(lex,tipot.ref,String.valueOf(postipo),campoDesp);
		    consumeToken();
			campoDesp+=ts.props(String.valueOf(postipo)).tamano();
			postipo++;
			return v;
			
		}
	else ERROR("Declaracion de registro erronea.");
	}
	return null;
}

private void DecVar() {
	if (categoria.equals("PALRES") && ((scanner.dameLexema().equals("real"))||(scanner.dameLexema().equals("int")))
			||(categoria.equals("IDEN") && ts.props(lex)!=null&&ts.props(lex).clase().equals("tipo"))){
		tipot t;
		String tipo=lex;
		if(scanner.dameLexema().equals("int"))tipo="integer";
		if(scanner.dameLexema().equals("pointer"))tipo="puntero";
		if(scanner.dameLexema().equals("rec"))tipo="rec";
		if(scanner.dameLexema().equals("real"))t=tipot.real;
		else if(scanner.dameLexema().equals("int"))t=tipot.integer;
		else t=tipot.ref;
		consumeToken();
		if(categoria.equals("CORCHETEABIERTO")){
			consumeToken();
			if(categoria.equals("NUMENTERO")){
				int numPos=Integer.parseInt(lex);
				consumeToken();
				if(categoria.equals("CORCHETECERRADO")){
					consumeToken();
					if(categoria.equals("IDEN")){
						if(ts.existeID(lex))ERROR("Nombre de variable ya utilizado.");
						else{
							
							int tamano=ts.props(tipo).tamano()*numPos;
						    ts.addID(String.valueOf(postipo), new RegistroProp(new PropsArray(tipot.array,tipo,numPos), "tipo", tamano));
						    compruebaPend(String.valueOf(postipo));
						    
							
						    PropsVar aux2 = new PropsVar(tipot.ref,String.valueOf(postipo),dir,"var");
							RegistroProp aux1 = new RegistroProp(aux2, "var", ts.props(String.valueOf(postipo)).tamano());
							ts.addID(lex,aux1);
						    
						    dir+=ts.props(String.valueOf(postipo)).tamano();
							consumeToken();
							if (!(categoria.equals("PUNTOYCOMA")))ERROR("Falta un ;");
							consumeToken();
							postipo++;
						}
					}else ERROR("La estructura no concuerda con un array");
				}else ERROR("La estructura no concuerda con un array");
			}else ERROR("La estructura no concuerda con un array");
		}else if (ts.existeID(lex,nivel))
			ERROR("Ya hay un identificador en la tabla con ese nombre");
		else{
			PropsVar aux2 = new PropsVar(t,tipo,dir,"var");
			RegistroProp aux1 = new RegistroProp(aux2, "var", ts.props(tipo).tamano());
			ts.addID(lex,aux1);
			dir+=ts.props(tipo).tamano();
			consumeToken();
			if (!(categoria.equals("PUNTOYCOMA")))ERROR("Falta un ;");
			consumeToken();
		}
		
	}else{
		if(categoria.equals("PALRES")&&lex.equals("rec")){
			consumeToken();
			PropsCampos c=Campos();
			if(!(categoria.equals("PALRES")&&lex.equals("endrec")))ERROR("falta fin de registro.");
			consumeToken();
			if(!categoria.equals("IDEN"))ERROR("Se esperaba nombre de registro.");
			else if(ts.existeID(lex))ERROR("Nombre de variable ya utilizado.");
			else{
				ts.addID(String.valueOf(postipo),new RegistroProp(c, "tipo", campoDesp) );
				compruebaPend(String.valueOf(postipo));
				
				PropsVar aux2 = new PropsVar(tipot.ref,String.valueOf(postipo),dir,"var");
				RegistroProp aux1 = new RegistroProp(aux2, "var", ts.props(String.valueOf(postipo)).tamano());
				ts.addID(lex,aux1);
				dir+=ts.props(String.valueOf(postipo)).tamano();
				consumeToken();
				if (!(categoria.equals("PUNTOYCOMA")))ERROR("Falta un ;");
				consumeToken();
				postipo++;
			}
				
		}else if(categoria.equals("PALRES")&&lex.equals("pointer")){
			consumeToken();
			if(ts.existeID(lex)&&ts.props(lex).clase()!="tipo")ERROR(lex+" no es un tipo.");
			String tipo = lex;
			if(scanner.dameLexema().equals("int"))tipo="integer";
			if(!ts.existeID(tipo))pend.add(lex);
			consumeToken();
			if(ts.existeID(lex))ERROR("Nombre ya utilizado.");
			ts.addID(String.valueOf(postipo), new RegistroProp(new Props(tipot.puntero, tipo), "tipo", 1));
			compruebaPend(String.valueOf(postipo));
			
			PropsVar aux2 = new PropsVar(tipot.ref,String.valueOf(postipo),dir,"var");
			RegistroProp aux1 = new RegistroProp(aux2, "var", ts.props(String.valueOf(postipo)).tamano());
			ts.addID(lex,aux1);
			dir+=ts.props(String.valueOf(postipo)).tamano();
			consumeToken();
			if (!(categoria.equals("PUNTOYCOMA")))ERROR("Falta un ;");
			consumeToken();
			postipo++;
			
		}
	}
	
}


private String Accs() {
	
	Acc();
	if(Terminar==true)return "err";
	
	if (!(categoria.equals("PUNTOYCOMA")))return ERROR("Falta un ;");
	encontrado=false;
	consumeToken();
	if (!(categoria.equals("PALRES")&&lex.equals("end")))
	RAccs();
	if(Terminar==true)return "err";
	return "";
	
}

private String RAccs() {
	
	
	if (!(categoria.equals("EOF")||(categoria.equals("PALRES")&&lex.equals("end")))){
		//categor�as por las que puede empezar una acci�n
		Acc();
		encontrado=false;
		if(Terminar==true)return "err";
		if (!(categoria.equals("PUNTOYCOMA"))){
			Terminar=true;
			return ERROR("Falta un ;");
		}else 
			consumeToken();
		RAccs();
		if(Terminar==true)return "err";
	}
	
	else{}
	return "";
	
}

private String As() {
	if (!(categoria.equals("PALRES")&&(lex.equals("fi")||lex.equals("else")||lex.equals("endwhile")||lex.equals("elsif")))){
	Acc();
	if(Terminar==true)return "err";
	if (!(categoria.equals("PUNTOYCOMA"))){
	    Terminar=true;
	    return  ERROR("Falta un ;");
	}
	encontrado=false;

	Ras();
	if(Terminar==true)return "err";
	return "";
	}
	return "";
}

private String Ras(){
	
	consumeToken();
	if (!(categoria.equals("PALRES")&&(lex.equals("fi")||lex.equals("else")||lex.equals("endwhile")||lex.equals("elsif")))){
		//categor�as por las que puede empezar una acci�n
		Acc();
		encontrado=false;
		if(Terminar==true)return "err";
		if (!(categoria.equals("PUNTOYCOMA"))){
			Terminar=true;
			return ERROR("Falta un ;");
		}else 
		Ras();
		if(Terminar==true)return "err";
	}
	
	else{}
	return "";
	
}


private String Acc() {
	String lex=scanner.dameLexema();
	if((categoria.equals("PALRES")&&(lex.equals("if")))){
		AcIf();
	}else if((categoria.equals("PALRES")&&(lex.equals("while")))){
			AcWhile();
	}else if((categoria.equals("PALRES")&&(lex.equals("return")))){
			AcReturn();
	}else if((categoria.equals("PALRES")&&(lex.equals("alloc")))){
			AcNew();
	}else if((categoria.equals("PALRES")&&(lex.equals("free")))){
			AcDel();
	}else{
			Exp0();
			emite("desapila()");
	}
	if(Terminar==true)return "err";
		
	return "";
}


private void AcReturn() {
	consumeToken();
	String tipo=Exp1();
	if(nivel==0)ERROR("No se pueden poner returns en nivel 0.");
	else if(!compatibles(tipo, tipoReturn))ERROR("no concuerda el valor retorno de la funcion y el del bloque de la funcion");
	emite("ir-a(---)");
	dirRetorno.add(etq);
	
}

private void AcDel() {
	consumeToken();
	String tipo=Mem();
	String tipoAux=ref(tipo);
	if(!ts.props(tipoAux).tipo().t().equals(tipot.puntero))ERROR("free necesita un puntero.");
	emite("apila-ind()");
	emite("del("+ts.props(tipoAux).tamano()+")");
	
}

private void AcNew() {
	consumeToken();
	String tipo=Mem();
	if(!tipo.equals("err")){
		String tipoAux=ref(tipo);
		if(!ts.props(tipoAux).tipo().t().equals(tipot.puntero))ERROR("Alloc necesita un puntero.");
		emite("new("+ts.props(tipoAux).tamano()+")");
		emite("desapila-ind()");
		emite("desapila()");
	}
	
}

private void AcWhile() {
	int etqAux=etq+1;
	consumeToken();
	Exp0();
	if(!(categoria.equals("PALRES")&&(lex.equals("do"))))ERROR("No se ha encontrado DO");
	consumeToken();
	emite("ir-f(...)");
	int etqAux1=etq;
	As();
	if(!(categoria.equals("PALRES")&&(lex.equals("endwhile"))))ERROR("No se ha encontrado ENDWHILE");
	consumeToken();
	emite("ir-a("+etqAux+")");
	parcheaF(etqAux1,etq+1);
}

private void AcIf()  {
	
	ArrayList<Integer> etqAux=new ArrayList<Integer>();
	consumeToken();
	Casos(etqAux); 
	Pelse();
	parcheaA(etqAux,etq+1);
	String lex=scanner.dameLexema();
	if(!(categoria.equals("PALRES")&&(lex.equals("fi"))))ERROR("No se ha encontrado fin de IF");
	consumeToken();
	
}

private void parcheaA(ArrayList<Integer> etqAux, int etqP) {
	for (int i=0;i<etqAux.size();i++){
		cod.remove(etqAux.get(i)-1);
		cod.add(etqAux.get(i)-1,"ir-a("+etqP+")");
	}
	
}

private void Pelse()  {
	String lex=scanner.dameLexema();
	if((categoria.equals("PALRES")&&(lex.equals("else")))){
		consumeToken();
		As();
	}else{}
	
}


private void Casos(ArrayList<Integer> etqAux)  {
	caso(etqAux);
	rCaso(etqAux);
	
}

private void rCaso(ArrayList<Integer> etqAux)  {
	//scanner.dameToken();
	String lex=scanner.dameLexema();
	if((categoria.equals("PALRES")&&(lex.equals("elsif")))){
		consumeToken();
		caso(etqAux);
		rCaso(etqAux);
	}else{}
	
}

private void caso(ArrayList<Integer> etqAux)  {

	Exp0();
	String lex=scanner.dameLexema();
	if((categoria.equals("PALRES")&&(lex.equals("then")))){
		consumeToken();
		int etqA=etq+1;
		emite("ir-f(...)");
		As();
		emite("ir-a(...)");
		etqAux.add(etq);
		parcheaF(etqA,etq+1);
	}else {ERROR("No se ha encontrado then");}
}

private void parcheaF(int etqA, int i) {
	cod.remove(etqA-1);
	cod.add(etqA-1,"ir-f("+i+")");
}

private String Exp0() {

	String lex=scanner.dameLexema();
	if ( (categoria.equals("PALRES"))&&(lex.equals("in"))){
			
		consumeToken();
		lex=scanner.dameLexema();
		String tipo=Mem();
		String tipoAux=ref(tipo);
		if(!(tipoAux.equals("integer")||tipoAux.equals("real")))return ERROR("tipo no compatible con in.");
		emite("in");
		emite("desapila-ind()");
		return ((PropsVar) ts.props(lex).tipo()).t().toString();
	}
	else if ( (categoria.equals("PALRES"))&&(lex.equals("out"))){//out Exp1
		
		consumeToken();
		lex=scanner.dameLexema();
		String tipo=Exp1();
		if(Terminar==true)return "err";
		emite("out");
		return tipo;
	}
	
	else 
		
		return Exp1();
}

private String Exp1() {
	String tipo;	

	
	if ((categoria.equals("IDEN"))){//de la clase iden = Exp1
		String iden=scanner.dameLexema();
		tipo=Exp2();
		if(Terminar==true)return "err";
		if (!(ts.existeID(iden)))return ERROR("El identificador no esta declarado en la tabla de simbolos");


		if ((categoria.equals("IGUAL"))){
			
			if (encontrado==true)return ERROR("no se esperaba un igual");
			par=false;
			encontrado=false;
			consumeToken();
			String tipo1;
			String tipoAux2="";
			if(categoria.equals("PALRES")&&scanner.dameLexema().equals("null")){
				tipo1="puntero";
				consumeToken();
				emite("apila(null)");
			}
			else {
				tipo1=Exp1();
				encontrado=false;
				if(Terminar==true)return "err";
				tipoAux2=ref(tipo1);
			}
			String tipoAux=ref(tipo);
			if (!(compatibles("=",tipoAux,tipoAux2)))return ERROR("No son compatibles el tipo del identificador y el de la expresion a la hora de hacer la asignacion");
			
			if(compatibles(tipoAux, "integer")||compatibles(tipoAux, "real")||ts.props(ref(tipoAux)).tipo().t()==tipot.puntero){
				emite("desapila-ind()");
			}else{ 
				if(compatibles(tipo1,tipo)){
					emite("mueve("+ts.props(tipo).tamano()+")");
					return tipo;
				}else 
					return ERROR("Tipos no compatibles en asignacion.");
			}
		}else {
			encontrado=false;
			return tipo;		  
		}
				  
	}else	 
		tipo=Exp2(); 
		return tipo;
		
}

private String Exp2() {
	
	
	String tipo=Exp3();
	if(Terminar==true)return "err";
	//if (encontrado==false)
	tipo=RExp2(tipo);
	return tipo;

}

private String RExp2(String tipo) {
	
	
	String lex=scanner.dameLexema();
	if ( (categoria.equals("MENOR"))||(categoria.equals("MAYOR"))||
			(categoria.equals("MENORIGUAL"))||(categoria.equals("MAYORIGUAL"))||
			(categoria.equals("IGUALCOMP"))||(categoria.equals("DISTINTO"))){
		par=false;
		encontrado=true;
		//tengo que leer un op2
		String op=categoria;
		if (categoria.equals("IGUALCOMP"))op="igual";
		consumeToken();
	
		String tipo1=Exp3();
		if(Terminar==true)return "err";
		if (!compatibles(lex,tipo,tipo1))return ERROR("Tipo de las expresiones no concordantes");
	
		emite(op.toLowerCase());
		return funop(lex,tipo,tipo1);
		
	}
	else {return tipo;}
		
		

	
}

private String Exp3() {	
	
	String tipo=Exp4();
	if(Terminar==true)return "err";
	tipo=RExp3(tipo);
	return tipo;

}

private String RExp3(String tipo) {
	
	String lexOp=scanner.dameLexema();
	if ((categoria.equals("OR"))||(categoria.equals("MAS"))||
			(categoria.equals("MENOS"))){
		par=false;
		encontrado=true;
		String op=categoria;
		if (categoria.equals("MENOS"))op="resta";
		else if(categoria.equals("MAS"))op="suma";
		
		consumeToken();
		String tipo1=Exp4();
		if(Terminar==true)return "err";
		if (!compatibles(lexOp,tipo,tipo1))return ERROR("Tipo de las expresiones no concordantes");
			
		tipo1=funop(lexOp,tipo,tipo1);
		tipo1=RExp3(tipo1);
		if(Terminar==true)return "err";
		emite(op.toLowerCase());
		return tipo;
	}
	else {return tipo;}
			
}

private String Exp4() {
			
	String tipo=Exp5();
	if(Terminar==true)return "err";
	tipo=RExp4(tipo);
	return tipo;
}

private String RExp4(String tipo) {
	
	String lex=scanner.dameLexema();
	if ((categoria.equals("MUL"))||(categoria.equals("DIV"))||
			(categoria.equals("MOD"))||(categoria.equals("AND"))){
		par=false;
		encontrado=true;
		String op=categoria;
		consumeToken();
		
		String tipo1=Exp5();
		if(Terminar==true)return "err";
		if (!compatibles(lex,tipo,tipo1))return ERROR("Tipo de las expresiones no concordantes");
	
		tipo1=funop(lex,tipo,tipo1);
		tipo1=RExp4(tipo1);
		if(Terminar==true)return "err";
		emite(op.toLowerCase());
		return tipo1;
	}
	else {return tipo;}
	
}

private String Exp5() {
	
	String lex=scanner.dameLexema();
	if ((categoria.equals("NEGADO"))||(categoria.equals("MENOS"))){
		String op="";
		par=false;
		if (categoria.equals("NEGADO"))op="not";
		else op="menosUnario";
		consumeToken();
		//op5
		String tipo=Exp5();
		if(Terminar==true)return "err";
		if (!compatible(lex,tipo))return ERROR("Tipo de las expresiones no concordantes");
	
		tipo=funopUnario(lex,tipo);
		emite(op);
		return tipo;
	}else //opn5
		if ((categoria.equals("PARABIERTO"))&&lex.equals("(")){
			consumeToken();
			lex=scanner.dameLexema();
			if ((categoria.equals("PALRES"))&&(lex.equals("int")||(lex.equals("real")))){
				par=false;
				String op="";
				if (lex.equals("int"))op="cInt";
				else op="cReal";
				consumeToken();
				lex=scanner.dameLexema();
				if ((categoria.equals("PARCERRADO"))&&lex.equals(")")){
					consumeToken();
					String tipo=Exp6();
					if(Terminar==true)return "err";
					if (!compatible(op,tipo))return ERROR("Tipo de las expresiones no concordantes");
				
					tipo=funopUnario(op,tipo);
					emite(op);
					return tipo;
					
				}else {
					    Terminar=true;
					    return ERROR("Se esperaba parentesis cerrado");
					}
			}else{
				lex=scanner.dameLexema();
				tipo=Exp0();
				if (Terminar==true)return "err";
				
				if (!(categoria.equals("PARCERRADO"))){
					ERROR("Parentesis no cerrado");
					Terminar=true;
				}	
				consumeToken();
				return tipo;
			}
		}
		else {
				tipo=Exp6();
				return tipo;
		}
}

private String Exp6() {
	//consumeToken();
	if ((categoria.equals("NUMENTERO"))||(categoria.equals("NUMDECIMAL"))||
			(categoria.equals("NUMEXPONENCIAL"))||(categoria.equals("NUMCERO"))){
			//Si es num
		par=false;
		String tipo=dameTipo(categoria);
		emite("apila("+scanner.dameLexema()+")");
		consumeToken();
		return tipo;
	}if (categoria.equals("PALRES")&&scanner.dameLexema().equals("null")){
		par=false;
		emite("apila(null)");
		consumeToken();
		if((categoria.equals("IGUAL")))return ERROR("La parte izquierda de una asignacion debe ser una variable");
		return tipo="null";
	}else if (categoria.equals("IDEN")){//si es iden
				if (!(ts.existeID(scanner.dameLexema())))return ERROR("No existe la variable");
				if(ts.props(lex)==null||ts.props(lex).clase().equals("fun"))
					tipo= llamadaFuncion();
				else{
					tipo=Mem();
					if(!(categoria.equals("IGUAL"))){
						if(compatibles(tipo, "integer")||compatibles(tipo, "real")||ts.props(ref(tipo)).tipo().t()==tipot.puntero)
							if(par!=true){
								emite("apila-ind()");
						}
					}
				}
				return tipo;
			}else if (categoria.equals("PARABIERTO")){//par�ntesis abierto
				consumeToken();
				tipo=Exp0();
				if (!(categoria.equals("PARCERRADO")))return ERROR("Parentesis no cerrado");
				consumeToken();
				
				return tipo;
			}else{
				return ERROR("Estructura de instruccion no encaja.");
			}
}

private String llamadaFuncion() {
	ArrayList<ParamFun> fparamts=((PropsFun) ts.props(lex).tipo()).params();
	int etqDirRet=etq+3;
	String aux=lex;
	apilaRet();
	//emite("apila-ret("+etqDirRet+")");
	AParam(fparamts);
	emite("ir-a("+((PropsFun) ts.props(aux).tipo()).dirInic()+")");
	parcheaRet(etqDirRet,etq+1);
	return ((PropsFun) ts.props(aux).tipo()).tRet();
	
}

private void parcheaRet(int etqDirRet, int i) {
	cod.remove(etqDirRet);
	cod.add(etqDirRet,"apila("+i+")");
}

private void apilaRet() {
	emite("apila-dir(0)");
	emite("apila(1)");
	emite("suma");
	emite("apila(...)");
	emite("desapila-ind()");
	emite("desapila()");
}

private void AParam(ArrayList<ParamFun> fparamts) {
	consumeToken();
	if(!categoria.equals("PARABIERTO"))ERROR("Se esperaba parentesis abierto.");
	else{
		consumeToken();
		if(categoria.equals("PARCERRADO")){consumeToken();}
		else{
			emite("apila-dir(0)");
			emite("apila(3)");
			emite("suma");
			listaExp(fparamts);
			emite("desapila()");
			
		}
	}
	
}

private void listaExp(ArrayList<ParamFun> fparamts) {
	emite("copia");
	boolean auxpar=par;
	if (fparamts.get(0).modo().equals("pvar"))
		par=true;
	else par=false;
	String tipo = Exp1();
	if (!compatibles(ref(tipo), ref(fparamts.get(0).t())))ERROR("No concuerdan el tipo de la llamada y la fncion.");
	else{
		if(fparamts.get(0).modo().equals("pvar")&&par==false)ERROR("No concuerda la cabecera con la llamada.");
		par=auxpar;
		emite("desapila-ind()");
		emite("desapila()");
		for(int i=1;i<fparamts.size();i++){
			if(!categoria.equals("COMA")){
				ERROR("Se esperaba una comaentre campos");
				break;
			}
			consumeToken();
			emite("copia");
			emite("apila("+fparamts.get(i).dir()+")");
			emite("suma");
			auxpar=par;
			if (fparamts.get(i).modo().equals("pvar"))
				par=true;
			else par=false;
			tipo = Exp1();
			if (!compatibles(ref(tipo), ref(fparamts.get(i).t())))ERROR("No concuerdan el tipo de la llamada y la fncion.");
			else{
				if(fparamts.get(i).modo().equals("pvar")&&par==false)ERROR("No concuerda la cabecera con la llamada.");
				par=auxpar;
				emite("desapila-ind()");
				emite("desapila()");
			}
		}
		if(!categoria.equals("PARCERRADO"))ERROR("Se esperaba parentesis cerrado.");
		consumeToken();
	}
}


/**/
private String Mem() {
if(ts.props(lex)==null||
		ts.props(lex).clase().equals("tipo"))
	return ERROR(lex+" no es una variable");
int dir = ((PropsVar) ts.props(lex).tipo()).dir();
//emite("apila("+dir+")");
int nivel=(ts.nivel(lex));
accesoVar(dir,nivel);
String tipoAux=ts.props(lex).tipo().t().toString();
if(tipoAux.equals("ref"))tipoAux=((PropsVar) ts.props(lex).tipo()).tBase();
//else if(ts.props(lex).tipo().t().equals(tipot.array))tipoAux=lex;
consumeToken();
tipoAux=RMem(tipoAux);
return tipoAux;
}

private void accesoVar(int dir,int nivel) {
	emite("apila-dir("+(1+nivel)+")"); 
	emite("apila("+dir+")"); 
	emite("suma"); 
	if(ts.props(lex).clase().equals("pvar"))emite("apila-ind()");
	
}

private String RMem(String tipo2) {
	if(categoria.equals("CORCHETEABIERTO")){
		String auxtipo=ref(tipo2);
		if(!ts.props(auxtipo).tipo().t().equals(tipot.array))return ERROR(auxtipo+" no es del tipo array.");
		consumeToken();
		boolean Auxencontrado=encontrado;
		encontrado=false;
		String tipo=Exp1();
		encontrado=Auxencontrado;
		if(!tipo.equals("integer"))ERROR("Error en el indice del array.");
		else if(categoria.equals("CORCHETECERRADO")){
			consumeToken();
			String aux;
			if(ts.props(tipo2).clase().equals("var"))aux=((PropsArray) ts.props(tipo2).tipo()).tBase();
			else  aux=((PropsArray) ts.props(tipo2).tipo()).tBase();
			emite("apila("+ts.props(aux).tamano()+")");
			emite("mul");
			emite("suma");
			return RMem(aux);
		}
			
	}else if(categoria.equals("PUNTO")){
		consumeToken();
		String auxtipo=ref(tipo2);
		if(ts.props(auxtipo).tipo().t()==tipot.rec){
			PropsCampos c=(PropsCampos) ts.props(auxtipo).tipo();
			if(c.ExisteCampo(lex)){
				String aux=c.getCampo(lex).tBase();
				emite("apila("+c.desp(lex)+")");
				emite("suma");
				consumeToken();
				return RMem(aux);
			}else ERROR("No hay un campo con ese nombre.");
		}else ERROR("No es registro.");
	
	}else if(categoria.equals("CIRCUNFLEJO")){
		consumeToken();
		String tipo=ref(tipo2);
		if(!ts.props(tipo).tipo().t().equals(tipot.puntero))return ERROR(tipo+" no es del tipo puntero.");
		emite("apila-ind()");
		String aux=(ts.props(tipo).tipo()).tBase();
		return RMem(aux);
	}
	return tipo2;
}

public void consumeToken(){
	try {
		categoria=scanner.dameToken();
		error();
		lex=scanner.dameLexema();
	} catch (IOException e) {
		System.out.println("Error al leer del archivo");
		e.printStackTrace();
	}
}


private boolean compatibles(String tipo1,String tipo2){
    ArrayList<String> visitados=new ArrayList<String>();
    return compatibles2(tipo1,tipo2,visitados);
}

private boolean compatibles2(String tipo1,String tipo2,ArrayList<String> visitados) {
	if (tipo1.equals("err")||tipo2.equals("err"))return false;
    if (visitados.contains(tipo1) && visitados.contains(tipo2))return true;
    else {visitados.add(tipo1);visitados.add(tipo2);}
    if ((ts.props(tipo1).tipo().t()).equals((ts.props(tipo2).tipo().t()))
    		&&((ts.props(tipo1).tipo().t()).equals(tipot.integer)))return true;
    if ((ts.props(tipo2).tipo().t()).equals(tipot.real)
    		&&((ts.props(tipo1).tipo().t()).equals(tipot.integer)))return true;
    if ((ts.props(tipo1).tipo().t()).equals((ts.props(tipo2).tipo().t()))
    		&&((ts.props(tipo1).tipo().t()).equals(tipot.real)))return true;
    if ((ts.props(tipo1).tipo().t()).equals(tipot.array)&&(ts.props(tipo2).tipo().t()).equals(tipot.array)&&((PropsArray) ts.props(tipo1).tipo()).numElems()==((PropsArray) ts.props(tipo2).tipo()).numElems())return compatibles2(((PropsArray) ts.props(tipo1).tipo()).tBase(),((PropsArray) ts.props(tipo2).tipo()).tBase(),visitados);
    if ((ts.props(tipo1).tipo().t()).equals(tipot.rec)&&(ts.props(tipo2).tipo().t()).equals(tipot.rec)&&((((PropsCampos) ( ts.props(tipo2)).tipo()).numCampos()==(((PropsCampos) ( ts.props(tipo2)).tipo()).numCampos())))){
    	ArrayList<Campo> c1=((PropsCampos) ts.props(tipo1).tipo()).getCampos();
    	ArrayList<Campo> c2=((PropsCampos) ts.props(tipo2).tipo()).getCampos();
    	for(int i=0;i<((PropsCampos) ts.props(tipo2).tipo()).numCampos();i++)
    		if(!compatibles2(c1.get(i).tBase(),c2.get(i).tBase(),visitados))return false;
        return true;
    }if((ts.props(tipo1).tipo().t()).equals(tipot.puntero)&&(ts.props(tipo2).tipo().t()).equals(tipot.puntero))
    	return compatibles2(ts.props(tipo1).tipo().tBase(),ts.props(tipo2).tipo().tBase(),visitados);
    if ((ts.props(tipo1).tipo().t()).equals(tipot.ref))return compatibles2((ts.props(tipo1).tipo().tBase()),tipo2,visitados);
    else if ((ts.props(tipo2).tipo().t()).equals(tipot.ref))return compatibles2(tipo1,(ts.props(tipo1).tipo().tBase()),visitados);
    return false;
}
private String ref(String s){
	if(ts.props(s).tipo().t().equals(tipot.ref))return ref(ts.props(s).tipo().tBase());
	return s;
}



}//Fin de clase
